//
//  OosManagedContext.m
//  Oos4ios
//
//  Created by Pablo Gonzalez on 3/18/11.
//  Copyright 2011 11870.com. All rights reserved.
//

#import "OosManagedContext.h"
#import "../Utils/SupportDirectory.h"
#import <oos4ios/Model/OosMetadata.h>
#import <CoreData/CoreData.h>

@implementation OosManagedContext

static OosManagedContext *mainContext = nil;
static NSManagedObjectModel *model = nil;
static NSPersistentStoreCoordinator *storeCoordinator = nil;

static NSMutableDictionary *threadContexts;

@synthesize isMain;

+ (OosManagedContext *) createContext
{
    OosManagedContext *context = nil;
    if (!model) {
        NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"oos4ios" ofType:@"bundle"];
        if (!bundlePath) {
            // TODO: create exception
            [NSException raise: @"No Bundle" format:@"The file oos4ios.bundle was not found in the main Bundle"];
        }
        NSURL *modelUrl = [NSURL fileURLWithPath:[[NSBundle bundleWithPath:bundlePath] pathForResource:@"oos_model" ofType:@"mom"]];
//        NSURL *modelUrl = [[NSBundle bundleWithPath:bundlePath] URLForResource:@"oos_model" withExtension:@"mom"];
        model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelUrl];
    }
    if (!storeCoordinator) {
        storeCoordinator = [[NSPersistentStoreCoordinator alloc] 
                            initWithManagedObjectModel: model];
        NSString *applicationSupportDirectory;
        applicationSupportDirectory = [SupportDirectory applicationSupportDirectory];
        NSURL *url = [NSURL fileURLWithPath: [applicationSupportDirectory 
                                              stringByAppendingPathComponent: @"oos_model.sqlite"]];
        NSError *error = nil;
        [storeCoordinator addPersistentStoreWithType:NSSQLiteStoreType 
                                       configuration:nil 
                                                 URL: url
                                             options: nil
                                               error:&error];
        if(error) {
            NSLog(@"An error occurred while adding the store coordinator: %@ - url: %@",
                  [error localizedDescription], url);
            storeCoordinator = nil;
            return nil;
        }
    }
    context = [[[OosManagedContext alloc] init] autorelease];
    [context setUndoManager:nil];
    [context setPersistentStoreCoordinator: storeCoordinator];
    [context setRetainsRegisteredObjects:YES];
    [context setMergePolicy: NSOverwriteMergePolicy];
    NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter];
    [dnc addObserver:context 
            selector:@selector(mergeChangesFromContextDidSaveNotification:) 
                name:NSManagedObjectContextDidSaveNotification 
              object:context];
    return context;
}

+ (OosManagedContext *) contextForCurrentThread
{
    if (!threadContexts) {
        threadContexts = [[NSMutableDictionary dictionary] retain];
    }
    OosManagedContext *threadContext;
    NSString *threadName = [[NSThread currentThread] name];
    threadContext = [threadContexts objectForKey:threadName];
    if (!threadContext) {
        threadContext = [self createContext];
        
        threadContext.isMain = NO;
        [threadContexts setValue:threadContext 
                          forKey:threadName];
    }
    return threadContext;
}

+ (OosManagedContext *) mainContext
{
    if (!mainContext) {
        mainContext = [[self createContext] retain];
        mainContext.isMain = YES;
    }
    return mainContext;
}

+ (OosManagedContext *) context
{
    if (![NSThread isMainThread]) {
        return [self contextForCurrentThread];
    }
    return [self mainContext];
}

+ (id) move: (id) object 
  toContext: (OosManagedContext *) targetContext
{
    id result = nil;
    if ([object isKindOfClass:[NSArray class]]) {
        NSArray *original = (NSArray *) object;
        NSMutableArray *resultArray;
        resultArray = [NSMutableArray arrayWithCapacity:[original count]];
        for (id item in original) {
            [resultArray addObject:[self moveObjectToMainContext:item]];
        }
        result = resultArray;
    } else if ([object isKindOfClass:[NSManagedObject class]]) {
        NSManagedObject *managedObject = (NSManagedObject *) object;
        NSManagedObjectID *objectID = [managedObject objectID];
        managedObject = [targetContext objectWithID:objectID];
        [targetContext refreshObject:managedObject mergeChanges:YES];
        result = managedObject;
    } else {
        NSLog(@"Can't move: %@", object);
    }
    return result;
}

+ (id)moveObjectToMainContext:(id)object
{
    return [self move:object toContext:[self mainContext]];
}

+ (id)moveObjectFromMainContext:(id)object
{
    return [self move:object toContext:[self context]];
}

+ (BOOL)clearContext
{
    
    NSString *applicationSupportDirectory;
    applicationSupportDirectory = [SupportDirectory applicationSupportDirectory];
    NSString *path = [applicationSupportDirectory 
                      stringByAppendingPathComponent: @"oos_model.sqlite"];
    NSURL *url = [NSURL fileURLWithPath: path];
    NSError *error = nil;
    NSFileManager *manager = [NSFileManager defaultManager];
    if ([manager respondsToSelector:@selector(removeItemAtURL:error:)]) {
        [[NSFileManager defaultManager] removeItemAtURL:url error: &error];
    } else {
        [[NSFileManager defaultManager] removeItemAtPath:path error: &error];
    }
    
    if (error) {
        NSLog(@"error deleting the model: %@", [error localizedDescription]);
        return NO;
    } else {
        [storeCoordinator release];
        storeCoordinator = nil;
        [OosMetadata reset];
        [mainContext release];
        mainContext = nil;
    }
    return YES;
}

- (BOOL)safeSave:(NSError **)error
{
    NSPersistentStoreCoordinator *coordinator = nil;
    coordinator = [self persistentStoreCoordinator];
    BOOL saved = NO;
    if ([coordinator tryLock]) {
        [[self persistentStoreCoordinator] lock];
        saved = [super save:error];
        [[self persistentStoreCoordinator] unlock];
    } else {
        saved = [super save:error];
    }
    
    return saved;
}

@end
